#!/usr/bin/python3
'''
Probably useless but functional IPv6 network scanner
This project was purely academic and I just wanted to learn about threading in Python.
To perform a regular (brute force) host scans in an IPv6 Network is almost impossible
it can take over 5.000 years to finish.
This software is not recommended for general usage.....
This piece of software will call the OS to actually perform the ping

This script receives two parameters:
a) Prefix to scan in the format 2001:db8::/64 (subnet, not host)
b) Number of simultaneous processes it can run

One more time it was purely academic stuff but hopefully it can make your day

Alejandro Acosta

Dec 2014

'''

import threading
import sys
import ipaddress
import subprocess
import time

CURRENTPINGS=0 #Just init the variable

def validateIPv6Address(ipv6address):
  ''' Function to determine if the IPv6 address passed as
  parameter is valid. Note that the scripts received also a prefix lenght
  '''
  isvalid = False
  try:
    if ipaddress.IPv6Network(ipv6address):
        #print (ipaddress.IPv6Network(ipv6address))
        isvalid=True
  except:
     pass
  return isvalid

def DOPING6(IPv6ADDRESS):
  global MAXPINGS, CURRENTPINGS
  CURRENTPINGS+=1
  CMD="ping6 -c 3 "+str(IPv6ADDRESS) + " 2> /dev/null > /dev/null"
  return_code = subprocess.call(CMD, shell=True) 
  if return_code == 0: 
    print (IPv6ADDRESS," is alive")
  
  CURRENTPINGS-=1
  
def main():
  global MAXPINGS, CURRENTPINGS
  if len(sys.argv) != 3: #Validate how many parameters we are receiving 
    print("  Not enough or too many parameter")
    print("  Usage: ./scanipv6.py IPv6Prefix/lenght MAXPINGS")
    print("  Example: ./scanipv6.py 2001:db8::/64 20")
    print("  Prefix lenght can be between 64-128")
    print("  MAXPINGS corresponds to how many pings will be running at the same time")
    exit()

  SUBNET,MASK=sys.argv[1].split("/")
  MAXPINGS=int(sys.argv[2])
  '''
  if validateIPv6Address(SUBNET) and int(MASK)>=64:
      print("ES VALIDA")
  else:
      exit()
  '''

  #print ("MYIP IS:",MYIP)
  for addr in ipaddress.IPv6Network(sys.argv[1]):  #Let's loop for each address in the Block
    ping_thread=threading.Thread(target=DOPING6,args=(addr,))

    while CURRENTPINGS >= MAXPINGS: # With this while we make it possible to run max simultaneous pings
      time.sleep(1)  # Let's wait one second before proceeding
      #print ("Interrumping...., CURRENTPINGS > MAXPINGS") #Uncomment this line just for debugging

    ping_thread.start()

main()
